#include "AppDelegate.h"
#include "EventHelper.h"

USING_NS_CC;

EventHelper::EventHelper(Node* targetNode, bool regEvent)
{
	thisNode = targetNode;
	for (int i = 0; i < 10; i++) isMouseKeyDown[i] = false;
	if (regEvent)
	{
		addMouseListener(
			[&](Event* e) { if (isEventFlagMatch()) { procMouseMove(e); onMouseMove(e); } },
			[&](Event* e) { if (isEventFlagMatch()) { procMouseDown(e); onMouseDown(e); } },
			[&](Event* e) { if (isEventFlagMatch()) { procMouseUp(e); onMouseUp(e); } },
			[&](Event* e) { if (isEventFlagMatch()) { procMouseMove(e); onMouseScroll(e); } },
			thisNode
		);
	}
}

void EventHelper::setEventFlagByBit(unsigned int flagbitpos)
{
	if (flagbitpos <= 16 && flagbitpos > 0)
	{
		eventFlag = 0x0001 << (flagbitpos - 1);
	}
}

void EventHelper::setEventFlag(unsigned int flag)
{
	eventFlag = flag;
}

unsigned int EventHelper::moveEventFlagUp()
{
	auto newflag = eventFlag << 1;
	if (newflag) eventFlag = newflag;
	return newflag;
}

unsigned int EventHelper::moveEventFlagDown()
{
	auto newflag = eventFlag >> 1;
	if (newflag) eventFlag = newflag;
	return newflag;
}

unsigned int EventHelper::getEventFlag()
{
	return eventFlag;
}

bool EventHelper::isEventFlagMatch()
{
	auto match = eventFlag&UI::getEventFlag();
	return match > 0 ? true : false;
}

bool EventHelper::isMouseHoverNode(Node * node, Event * e, int angelZ, float orbitOffsetX, float orbitWidth)
{
	Vec2 layerPos = node->convertToWorldSpace(Vec2::ZERO);
	auto nodesize = pUI->getNodeScaledSize(node);
	Rect rect = Rect(layerPos, nodesize);
	Vec2 mouseLoc;
	if (angelZ == 0)
	{
		mouseLoc = ((EventMouse*)e)->getLocationInView();
	}
	else
	{
		auto orbitPosX = layerPos.x - orbitOffsetX;
		if (orbitWidth == 0) orbitWidth = nodesize.width;
		mouseLoc = UI::convertOrbitPos(((EventMouse*)e)->getLocationInView(), orbitPosX, orbitWidth, angelZ);
	}
	return rect.containsPoint(mouseLoc);
}

bool EventHelper::isMouseHoverArea(Vec2 position, Size size, Event * e)
{
	Point mouseLoc = ((EventMouse*)e)->getLocationInView();
	Rect rect = Rect(position, size);
	return rect.containsPoint(mouseLoc);
}

bool EventHelper::isPointInNode(Node * node, Vec2 point)
{
	Vec2 layerPos = node->convertToWorldSpace(Vec2::ZERO);
	auto nodesize = pUI->getNodeScaledSize(node);
	Rect rect = Rect(layerPos, nodesize);
	return rect.containsPoint(point);
}

bool EventHelper::isMouseKey(MouseKey key, Event * e)
{
	return ((EventMouse*)e)->getMouseButton() == key ? true : false;
}

Vec2 EventHelper::getMouseLoc(Event * e)
{
	return ((EventMouse*)e)->getLocationInView();
}

Vec2 EventHelper::getMouseLocInNode(Node * node, Event * e)
{
	auto mouseloc = ((EventMouse*)e)->getLocationInView();
	auto loc = node->convertToNodeSpace(mouseloc);
	//loc.y = pUI->getNodeScaledSize(node).height - loc.y;
	return loc;
}

void EventHelper::addMouseListener(function<void(Event*)> onMove,
								   function<void(Event*)> onDown,
								   function<void(Event*)> onUp,
								   function<void(Event*)> onScroll,
								   Node* targetNode)
{
	auto mouseListener = EventListenerMouse::create();
	mouseListener->onMouseMove = onMove;
	mouseListener->onMouseDown = onDown;
	mouseListener->onMouseUp = onUp;
	mouseListener->onMouseScroll = onScroll;
	Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(mouseListener, targetNode);
}

void EventHelper::setAdditionalEventAction(MouseEventType mouseEventType, function<void()> func)
{
	switch (mouseEventType)
	{
		case MOUSEMOVE:
			additionalEventActions.onMouseMove = func;
			break;
		case MOUSEDOWN:
			additionalEventActions.onMouseDown = func;
			break;
		case MOUSEUP:
			additionalEventActions.onMouseUp = func;
			break;
		case MOUSESCROLL:
			additionalEventActions.onMouseScroll = func;
			break;
		default: return;
	}
}

void EventHelper::runAdditionalEventAction(MouseEventType mouseEventType)
{
	switch (mouseEventType)
	{
		case MOUSEMOVE:
			if (additionalEventActions.onMouseMove) additionalEventActions.onMouseMove();
			break;
		case MOUSEDOWN:
			if (additionalEventActions.onMouseDown) additionalEventActions.onMouseDown();
			break;
		case MOUSEUP:
			if (additionalEventActions.onMouseUp) additionalEventActions.onMouseUp();
			break;
		case MOUSESCROLL:
			if (additionalEventActions.onMouseScroll) additionalEventActions.onMouseScroll();
			break;
		default: return;
	}
}

void EventHelper::procMouseMove(Event * e)
{
	//bool ishover;
	//if (orbit == 0)	ishover = isMouseHoverNode(thisNode, e);
	//else ishover = isMouseHoverNode(thisNode, e, orbit, thisNode->getPositionX(), thisNode->getContentSize().width);
	auto ishover = isMouseHoverNode(thisNode, e);
	if (ishover)
	{
		switch (mouseStatus)
		{
			case MOUSEOUTER:mouseStatus = MOUSEENTER; break;
			case MOUSEENTER:mouseStatus = MOUSEHOVER; break;
			case MOUSEHOVER:mouseStatus = MOUSEHOVER; break;
			case MOUSELEAVE:mouseStatus = MOUSEENTER; break;
			default:break;
		}
	}
	else
	{
		switch (mouseStatus)
		{
			case MOUSEOUTER:mouseStatus = MOUSEOUTER; break;
			case MOUSEENTER:mouseStatus = MOUSELEAVE; break;
			case MOUSEHOVER:mouseStatus = MOUSELEAVE; break;
			case MOUSELEAVE:mouseStatus = MOUSEOUTER; break;
			default:break;
		}
	}
}

void EventHelper::procMouseDown(Event * e)
{
	mouseKey = ((EventMouse*)e)->getMouseButton();
	isMouseKeyDown[mouseKey] = true;
}

void EventHelper::procMouseUp(Event * e)
{
	mouseKey = ((EventMouse*)e)->getMouseButton();
	isMouseKeyDown[mouseKey] = false;
}
